<?php
/**
 * D5Power Studio d5power Webgame Engine
 *
 * Extends DOTK system
 * Author: D5Power Studio
 *
 *
 * 第五动力工作室 d5power网页游戏引擎 Ver 1.0
 * 继承自:DOTK引擎
 * 作者：第五动力工作室
 */
/** PAGE NOT ALLOWED
 * Verify if user called this page through a allowed page.
 * @message: That file cannot be displayed alone.
 */
if (!isset($allowed_page)) { echo "That file cannot be displayed alone."; exit; }

require_once("d5power.DAO.php");

//Dotk character class.
class Character extends DAO {

  public $character_id;
  public $name;
  public $profession;
  public $posx;
  public $posy;
  public $str;
  public $dex;
  public $int;
  public $vit;
  public $agi;
  public $money;
  public $offlinetime;
  public $busy;
  public $state;
  public $xp;
  public $gender;
  public $level;
  public $map_id;
  public $avatar;
  public $uid;
  public $lastmove;
  public $hp;
  public $alive;
  public $attack;
  public $relife_mid;
  public $relife_posx;
  public $relife_posy;
  
  /**
  * Constructor function
  * @param
  */
  public function Character() {
	//nothing for while
  }

  /**
  * Function "load"
  * @description Used to retrieve for DB all character's attributes
  * identified for the given 'characterId'.
  */
  public function load($characterId) {
    $sql = "SELECT * FROM characters WHERE cid = ?";
    $queryResult = $this->retrieve($sql, array($characterId));
    $result = $queryResult->getRow();

	$this->character_id = $result['cid'];
	$this->uid			= $result['uid'];
    $this->charactername = $result['charactername'];
    $this->profession = $result['profession'];
    $this->posx = $result['posx'];
    $this->posy = $result['posy'];
    $this->str = $result['_str'];
    $this->dex = $result['_dex'];
    $this->int = $result['_int'];
    $this->vit = $result['_vit'];
    $this->agi = $result['_agi'];
    $this->money = $result['money'];
    $this->offlinetime = $result['offlinetime'];
    $this->busy = $result['busy'];
    $this->state = $result['state'];
    $this->xp = $result['xp'];
    $this->level = $result['lv'];
    $this->map_id = $result['mid'];
	$this->avatar = $result['avatar'];
	$this->online = $result['online'];
	$this->attack= $result['_atk'];
    $this->defense= $result['_def'];
    $this->hasdefended= $result['_hasdef'];
    $this->hp = $result['hp'];
	$this->gender = $result['gender'];
    $this->availablepoints= $result['availablepoints'];
	$this->lastmove = $result['lastmove'];
	$this->relife_mid = $result['relife_mid'];
	$this->relife_posx = $result['relife_posx'];
	$this->relife_posy = $result['relife_posy'];
	$this->alive = true;
  }
  
  /**
   *
   *
   *
   */
  
  public function offlineMyOtherCharacter()
  {
  	$sql = "update characters set online = 0 where uid= ? and online=1 and cid!= ?";
	$this->retrieve($sql,array($this->uid,$this->character_id));
  }
  /**
  * Function "create"
  * @description Creates a new character on DB.
  */
  function create($name, $gender, $avatar) {
  
    $sql = "insert into characters (uid, charactername, gender, avatar, posx, posy, mid,relife_mid,relife_posx,relife_posy) values(?, ?, ?, ?, 20, 14, 1, 1, 20, 14)";
    try {
	if($name==""){
  		throw new Exception("请填写角色名！点击<a href=\"create_character.php\">这里</a>重新填写");	
		exit;
    	}	
      $this->retrieve($sql, array($_SESSION['playerId'], $name, $gender, $avatar));
      return true;
    }
    catch(Exception $e) {
      return $e->getMessage();
    }
  }
    
  public function save() {
    $sql = "update
              characters
            set
              charactername = ?,
              profession = ?,
              posx = ?,
              posy = ?,
              _str = ?,
              _dex = ?,
              _int = ?,
              _vit = ?,
              _agi = ?,
              money = ?,
              offlinetime = ?,
              busy = ?,
              state = ?,
              xp = ?,
              lv = ?,
              mid = ?,
              avatar = ?,
              online = ?,
              _atk= ?,
              _def= ?,
              _hasdef= ?,
              availablepoints= ?,
              hp=?
            where
              cid = ?";

    $result = $this->retrieve($sql, array($this->charactername,
                                          $this->profession,
                                          $this->posx,
                                          $this->posy,
                                          $this->str,
                                          $this->dex,
                                          $this->int,
                                          $this->vit,
                                          $this->agi,
                                          $this->money,
                                          $this->offlinetime,
                                          $this->busy,
                                          $this->state,
                                          $this->xp,
                                          $this->level,
                                          $this->map_id,
                                          $this->avatar,
                                          $this->online,
                                          $this->attack,
                                          $this->defense,
                                          $this->hasdefended,
                                          $this->availablepoints,
                                          $this->hp,
                                          $this->character_id));
    return true;
  }
  
  public function gainMoney($money) {
    $this->money += $money;
    $sql = "UPDATE character SET money = ? where c = ? ";
    $playerResult = $this->retrieve($sql, arary($money, $this->character_id));
  }
  
  public function loseMoney($money) {
    if(($this->money-$money) < 0 ){
      $this->money -= $money;
      $sql = "UPDATE personagem SET dinheiro = ? where idpersonagem = ? ";
      $playerResult = $this->retrieve($sql, $money);
    }
  }
  
  public function gainXp($amount) {
   $this->xp+= $amount;
   $sql = "UPDATE characters SET xp = ? where cid = ? ";
   $playerResult = $this->retrieve($sql, array($this->xp, $this->character_id));
  }
  
  public function isLevelUp() {
  	$nextExp = 50 * ($this->level+1) + pow(($this->level+1),4);
    if($this->xp>=$nextExp) {
      $this->level += 1;
	  $this->xp = 0;
      // Como adicionar os pontos....?
      	$sql = "UPDATE characters SET lv = lv+1,xp=0 where cid = ? ";
   		$playerResult = $this->retrieve($sql, array($this->character_id));
      	return true;
    }else{
		return false;
	}
  }
  
  public function acceptTrade(){
       $this->busy= 1;
       $this->status= "AcceptedTrade";
  }
  
  public function Death()
  {
  		$this->hp=1;
		$this->setMap_id($this->relife_mid);
		$this->setPosx($this->relife_posx);
		$this->setPosy($this->relife_posy);
		$sql = 'update characters set hp=1,mid=relife_mid,posx=relife_posx,posy=relife_posy where cid=?';
		$this->retrieve($sql, array($this->character_id));
  }
	
	/* --------------- Advance Function -------------- */
	/**
	 * Function attack
	 * @description Used on battles to hit the opponent.
	 * @param {Character} $rival An instance of your opponent character.
	 * @return {Array}
	 */
	public function attack($rival)
	{
		$this->undefend();
		//Frist roll the dice.
		$dice = rand(1,20);
		$message = "";
		$result = array();
	
		/*
		* Damage calc in accordance with D20 System
		*/
	
		//if dice results 1 (minimum) = critical miss
		//5%几率
		if($dice == 1)
		{
			$damage = 0;
			$message = "LUCK";
		}else{
			//if dice results 20 (maximum) - critical attack
			if($dice == 20)
			{
				$damage = ($this->attack + floor($this->str/6))*2;
				$message = "CRI";
			}else{
				
				$miss_dice = 10+20*($this->level+$this->dex/280); //基本50%命中
				if($dice<$miss_dice) //$rival->defense < ($dice + floor($this->vit/8))
				{
					// 300攻击满额
					// 按比例计算防御
					// 150 DEX满额
					$min_atk = 1+$this->attack*($this->dex/150);
					$damage = rand($min_atk, $this->attack) + floor($this->str/6);
					$damage = floor($damage*(1-($rival->defense/300)*0.6)); // 300防减60%攻击
					$message = "ATK";
				}else{
					$damage = 0;
					$message = "MISS";
				}
			}
			
			$rival->hurt($damage);
		}
	
	$result["message"] = $message;
	$result["damage"] = $damage;
	
	//$target->load($rival);
	//$target->receiveDamage($damage);
	
	return $result;
	}
	
	
	public function undefend()
	{
		if($this->hasdefended)
		{
			$this->defense-= 6;
			$this->hasdefended=0;
		}
	}
  
  // Getters and Setters
  public function getcharacterId() {
    return $this->character_id;
  }

  public function setcharacterId($characterId) {
	$this->character_id = $characterId;
  }
  
  // 获得物品
  public function getItem($item_id,$num=1)
  {
  	$max_class=60;		//背包最大分类
	$max_item = 99;		//单物品最多数量
  
  	if($num<=0) return 'ZERO';
	$num = $num>$max_item ? $max_item : $num;
	
	
  	// 检查背包容量备用，因为要根据食品/其他种类判断
	$sql = 'select count(cid) as max from character_package where cid=? and item_id!=?';
	$db=$this->retrieve($sql,array($this->character_id,$item_id));
	$result = $db->getRow();
	
  	// 检查物品种类
	$sql = 'select id,_caneat from item where id=?';
	$db=$this->retrieve($sql,array($item_id));
	if($db->isEmpty()) return 'ERROR';
	$item = $db->getRow();
	if($item['_caneat']==1)
	{
		// 可以吃，累加
		$sql = 'select * from character_package where cid=? and item_id=?';
		$db=$this->retrieve($sql,array($this->character_id,$item_id));
		if(!$db->isEmpty())
		{
			$item_inpackage = $db->getRow();
			if($item_inpackage['_number']==$max_item) return 'ITEMFULL';
			$new_number=$item_inpackage['_number']+$num;
			if($new_number>$max_item)
			{
				$sql = 'update character_package set _number='.$max_item.' where id=?';
				$this->retrieve($sql,array($item_inpackage['id']));
				return 'FULLOK'; // 丢弃累加
			}else{
				$sql = 'update character_package set _number=? where id=?';
				$this->retrieve($sql,array($new_number,$item_inpackage['id']));
				return 'OK'; // 完成
			}
		}else{
			if(($result['max']+1)>$max_class) return 'FULL'; //种类已满
			
			$sql = 'insert into character_package set cid=?,item_id=?,_number=?';
			$this->retrieve($sql,array($this->character_id,$item_id,$num));
			return 'OK';
		}
	}else{
		if(($result['max']+1)>$max_class) return 'FULL'; //种类已满
		
		$sql = 'insert into character_package set cid=?,item_id=?,_number=?';
		$this->retrieve($sql,array($this->character_id,$item_id,$num));
		return 'OK';
	}
	
  }
  
  public function useItem($item_id)
  {
  	// 检查物品是否属于本人
	$sql = 'select item_id,cid,id,_number from character_package where cid=? and item_id=?';
	$db=$this->retrieve($sql,array($this->character_id,$item_id));
	if($db->isEmpty()) return 'ERROR:Not your item';
	$package=$db->getRow();
	
	// 检查物品种类
	$sql = 'select _canequ,_caneat,_caninlay,id from item where id=? ';
	$db=$this->retrieve($sql,array($item_id));
	if($db->isEmpty()) return 'ERROR';
	$item = $db->getRow();
	if($item['_canequ']==1)
	{
		// 可装备物品
		$sql = 'select _needlv,_str,_vit,_dex,_int,_agi,_atk,_def,_speed,_where,id from item where id=?';
		$db = $this->retrieve($sql,array($item['id']));
		$will = $db->getRow();
		
		// 查询已装备在该位置的装备
		$sql = 'select cid,item_id,_where,id,pid from character_equipment where cid=? and _where=?';
		$db = $this->retrieve($sql,array($this->character_id,$will['_where']));
		if(!$db->isEmpty())
		{
			$temp = $db->getRow();
			// 如果装备的是同件物品，返回
			if($temp['item_id']==$will['id']) return 'SAME';
			// 装备了物品，将其卸下
			$sql = 'select _str,_vit,_dex,_int,_agi,_atk,_def,_speed,_where,id from item where id=?';
			$db = $this->retrieve($sql,array($temp['item_id']));
			$drop = $db->getRow();
			
			// 重新设置属性
			$this->str -= $drop['_str'];
			$this->dex -= $drop['_dex'];
			$this->int -= $drop['_int'];
			$this->vit -= $drop['_vit'];
			$this->agi -= $drop['_agi'];
			$this->attack-= $drop['_atk'];
    		$this->defense-= $drop['_def'];	
			
			// 设置装备的包裹状态为未安装
			$sql = 'update character_package set _isequed =0 where id=?';
			$this->retrieve($sql,array($temp['pid']));
			
			// 安装装备
			$sql = 'update character_equipment set item_id=?,pid=? where id=?';
			$this->retrieve($sql,array($will['id'],$package['id'],$temp['id']));
		}else{
			// 安装装备
			$sql = 'insert into character_equipment set item_id=?,cid=?,_where=?,pid=?';
			$this->retrieve($sql,array($will['id'],$this->character_id,$will['_where'],$package['id']));
		}
		
		$sql = 'update character_package set _isequed=1 where id=?';
		$this->retrieve($sql,array($package['id']));
		
		// 更新属性
		$this->str += $will['_str'];
		$this->dex += $will['_dex'];
		$this->int += $will['_int'];
		$this->vit += $will['_vit'];
		$this->agi += $will['_agi'];
		$this->attack+= $will['_atk'];
		$this->defense+= $will['_def'];
		
		$this->save();
		
		// 制作返回数组
		$arr = array(
			'str'	=>	$this->str,
			'dex'	=>	$this->dex,
			'int'	=>	$this->int,
			'vit'	=>	$this->vit,
			'agi'	=>	$this->agi,
			'atk'	=>	$this->attack,
			'def'	=>	$this->defense,
		);
		
		return $arr;
	}else if($item['_caninlay']==1){
		// 可镶嵌物品
		return 'NOTOPEN';
	}else if($item['_caneat']==1){
		if($package['_number']<=0) return 'NOITEM';
		// 可食用物品
		$sql = 'select _mp,_hp,id from item where id=?';
		$db=$this->retrieve($sql,array($item['id']));
		$result=$db->getRow();
		// 减少食品数量
		$package['_number']-=1;
		if($package['_number']<=0)
		{
			$sql = 'delete from character_package where id=?';
			$this->retrieve($sql,array($package['id']));
		}else{
			$sql = 'update character_package set _number=? where id=?';
			$this->retrieve($sql,array($package['_number'],$package['id']));
		}
		
		$temp = $this->hp+$result['_hp'];
		$result_hp = $temp > $this->getMaxHp() ? $this->getMaxHp() : $temp;
		$this->setHp($result_hp);
		$this->save();
		
		$arr = array(
			'hp'	=>	$result_hp,
			//'mp'	=>	$result['_mp'],
			'left'	=>	$package['_number'],
		);
		
		return $arr;
	}else{
		return 'CAN NOT USE';
	}
  }
  
  // 背包列表
  public function myPackage()
  {
	$sql = 'select p.item_id,p.cid,p._number,';
	$sql .= 'i.id,i._name,i._info from character_package as p LEFT JOIN item as i ON (p.item_id=i.id) where p._isequed = 0 and  p.cid=?';
	$db=$this->retrieve($sql,array($this->character_id));
	if($db->isEmpty()) return '';
	
	$mypackage=array();
	for($i=0;$i<count($db->getArray());$i++)
	{
		$item = $db->getRow();
		$arr = array(
			'id'		=>	$item['id'],
			'name'		=>	$item['_name'],
			'info'		=>	$item['_info'],
			'num'		=>	$item['_number'],
		);
		
		array_push($mypackage,$arr);
	}
	
	return $mypackage;
  }

  public function getname() {
	return $this->name;
  }

  public function setname($name) {
	$this->name = $name;
  }

  public function getProfession() {
	return $this->profession;
  }

  public function setProfession($profession) {
	$this->profession = $profession;
  }

  public function getPosx() {
	return $this->posx;
  }

  public function setPosx($positionX) {
	$this->posx = $positionX;
  }

  public function getPosy() {
	return $this->posy;
  }

  public function setPosy($positionY) {
	$this->posy = $positionY;
  }

  public function getstr() {
	return $this->str;
  }

  public function setstr($str) {
	$this->str = $str;
  }

  public function getdex() {
	return $this->dex;
  }

  public function setdex($dex) {
	$this->dex = $dex;
  }

  public function getint() {
	return $this->int;
  }

  public function setint($int) {
	$this->int = $int;
  }

  public function getvit() {
	return $this->vit;
  }

  public function setvit($vit) {
	$this->vit = $vit;
  }

  public function getagi() {
	return $this->agi;
  }

  public function setagi($agi) {
	$this->agi = $agi;
  }

  public function getmoney() {
	return $this->money;
  }

  public function setmoney($money) {
	$this->money = $money;
  }

  public function getofflineHours() {
	return $this->offlineHours;
  }

  public function setofflineHours($offlineHours) {
	$this->offlineHours = $offlineHours;
  }

  public function getbusy() {
	return $this->busy;
  }

  public function setbusy($busy) {
	$this->busy = $busy;
  }

  public function getstate() {
	return $this->state;
  }

  public function setstate($state) {
	$this->state = $state;
  }

  public function getxp() {
	return $this->xp;
  }

  public function setxp($xp) {
	$this->xp = $xp;
  }

  public function getlevel() {
	return $this->level;
  }

  public function setlevel($level) {
	$this->level = $level;
  }
  
  public function getActualMap() {
  	return $this->map_id;
  }
  
  public function setActualMap($mapId) {
  	$this->map_id = $mapId;
  }

	public function getMap_id()
	{
	  return $this->map_id;
	}
	
	public function setMap_id($map_id)
	{
		$this->map_id = $map_id;
	}
	
	public function getOnline()
	{
    	return $this->online;
	}

	public function setOnline($online)
	{
    	$this->online = $online;
	}
	
	public function offLine()
	{
		$this->setOnline(0);
		$this->save();
	}
	
	public function getLastmove()
	{
		return $this->lastmove;
	}
	
	public function getHp()
	{
		return $this->hp;
	}
	
	public function setHp($hp)
	{
		$this->hp=$hp;
	}
	
	public function getMaxHp()
	{
		return (40*$this->level + pow(floor($this->vit/6),3));
	}
	
	public function hurt($hp)
	{
		$myHp = $this->getHp();
		$myHp -= $hp;
		if($myHp<=0)
		{
			$this->setHp(1);
			$this->alive = false;
		}else{
			$this->setHp($myHp);
		}
	}
	
	public function isLive()
	{
		return $this->alive;
	}
}

//Test Unit
/*
  $c = new Character();
  $c->load(1);
  print_r($c);
*/

?>
